package com.bracelet.util.netty;

import cn.hutool.extra.spring.SpringUtil;
import com.bracelet.Enum.DeviceStateEnum;
import com.bracelet.config.CacheConfig;
import com.bracelet.mapper.IDeviceInfoMapper;
import com.bracelet.pojo.entity.IDeviceInfo;
import com.bracelet.pojo.entity.CCacheDictionary;
import com.bracelet.service.IDeviceInfoService;
import com.bracelet.service.impl.IDeviceInfoServiceImpl;
import com.bracelet.util.MessageFormatUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.util.concurrent.GlobalEventExecutor;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.assertj.core.util.DateUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;
import reactor.util.function.Tuple2;
import reactor.util.function.Tuple3;
import reactor.util.function.Tuples;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketTimeoutException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;

@Slf4j
@Component
/*不加这个注解那么在增加到childHandler时就必须new出来*/
@ChannelHandler.Sharable
public class NettyServerHandler extends SimpleChannelInboundHandler<String> {

    private static SimpleDateFormat sdf = null;

    static {
        sdf = new SimpleDateFormat("yyMMddHHmmss");
    }

    private byte[] req;

    private int counter;


    //保留所有与服务器建立连接的channel对象
    private static ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

    // 读取客户端消息
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        log.info("收到请求：{}",msg);
        // 校验数据是否合规
        Tuple3<Boolean,String,String> tuples= MessageFormatUtil.checkMsg(msg);
        Boolean isTrue = tuples.getT1();
        String bizKey = tuples.getT2();
        String serviceId = tuples.getT3();
        if(isTrue){
            CCacheDictionary dictionary = CacheConfig.getDictionaryByItem("ServiceUrl", serviceId);
            if(dictionary == null){
                log.info("未识别的交易码{},请确认配置或上送数据收否有误",serviceId);
                return;
            }
            String url = dictionary.getItemvalue();
            // 判断当前连接是否为新连接
            Tuple2<Boolean, NettySession> newSession = isNewSession(bizKey, ctx);
            Boolean isNewSession = newSession.getT1();
            NettySession nettySession = newSession.getT2();
            nettySession.setBizKey(bizKey);
            if (isNewSession) {
                NettySessionManager.addSession(nettySession);
                //jdbc存数据 系统压力估计会不小谨慎决定是否开发 不行就塞redis
                deviceOnline(bizKey);
            }
            // handleMessage(dataPacket);

            RestTemplate restTemplate = new RestTemplate();
            ObjectMapper mapper = new ObjectMapper();
            ObjectNode objectNode = mapper.createObjectNode();
            objectNode.put("args",msg);
            objectNode.put("className",dictionary.getAttributevalue1());
            ResponseEntity<ObjectNode> response
                    = restTemplate.postForEntity(url, objectNode, ObjectNode.class);
            if(response.getBody()!=null&& !StringUtils.isEmpty(response.getBody().get("args").asText())){
                ctx.channel().writeAndFlush(response.getBody().get("args").asText());
            }
        }
    }

    /**
     * 判断当前连接是否是新链接
     *
     * @param bizKey 设备id
     * @param ctx    ChannelHandlerContext
     * @return
     */
    private Tuple2<Boolean, NettySession> isNewSession(String bizKey, ChannelHandlerContext ctx) {
        boolean isNewSession = true;
        Optional<NettySession> optionalSession = NettySessionManager.getSession(ctx);
        NettySession currentSession = null;
        if (optionalSession.isPresent()) {
            // 存在session，代表非第一次连接
            isNewSession = false;
            currentSession = optionalSession.get();
            currentSession.setLastTime(LocalDateTime.now());
            log.info("----------旧TCP连接[有Session]----------, bizKey=[{}], channelId=[{}]", bizKey, currentSession.getChannelId());
        } else {
            currentSession = NettySession.build(bizKey, ctx);
            log.info("----------新TCP连接[无Session]----------, bizKey=[{}], channelId=[{}]", bizKey, ctx.channel().id().asLongText());
        }
        return Tuples.of(isNewSession, currentSession);
    }

//    private void handleMessage(String dataPacket) throws Exception {
//        if (dataPacket == null) {
//            return;
//        }
//        String commandCode = dataPacket.getCommand(); // 命令
//        String strMessage = JSON.toJSONString(dataPacket);
//        MsgSender msgSender = SpringUtil.getBean(MsgSender.class);
//        switch (commandCode) {
//            case ComConstant.CommandUp.SENTRY_HEARTBEAT:
//                // 发送设备心跳消息
////                System.out.println("数据上报，接收心跳数据：" + strMessage);
//                msgSender.asyncSendDeviceUpHeartBeat(strMessage);
//                break;
//            case ComConstant.CommandUp.SENTRY_RADAR_STATUS:
//                // 雷达数据上报参数
////                System.out.println("数据上报，接收雷达数据：" + strMessage);
//                msgSender.syncSendDeviceUpRadar(strMessage);
//                break;
//            default:
//                //除了心跳，雷达以外的，所有数据上报
//                msgSender.asyncSendDeviceUpCommand(strMessage);
//                break;
//        }
//    }

    /*
     * 数据读取完毕
     *
     * 覆盖 channelActive 方法 在channel被启用的时候触发 (在建立连接的时候)
     *
     * */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        log.info("连接的客户端地址 : " + ctx.channel().remoteAddress() + " active !");
        // 获取业务键（假设从Channel获取业务键的方法）
        String bizKey = ctx.channel().id().asLongText();
        if (!NettySessionManager.isHaveSessionId(bizKey)) {
            List<NettySession> existingSessions = NettySessionManager.getSessionByBizKey(bizKey);
            if (!existingSessions.isEmpty()) {
                log.warn("Existing sessions found for bizKey: {}, removing old sessions", bizKey);
                for (NettySession session : existingSessions) {
                    NettySessionManager.removeSession(session.getChannel().id().asLongText());
                }
            }
        }

        super.channelActive(ctx);
    }

    // 设备上线
    private void deviceOnline(String bizKey) {
        log.info("----------设备：{}，上线！---------", bizKey);
        if (bizKey == null) {
            return;
        }
      IDeviceInfoService deviceTerminalService = SpringUtil.getBean(IDeviceInfoServiceImpl.class);
        IDeviceInfo deviceTerminal = deviceTerminalService.getById(bizKey);
        if(deviceTerminal == null){
            deviceTerminal = new IDeviceInfo();
            deviceTerminal.setDevicetime(DateUtil.now());
        }
        deviceTerminal.setDevideid(bizKey);
        deviceTerminal.setOnlinetime(DateUtil.now());
        deviceTerminal.setOfflinetime(null);
        deviceTerminal.setStatus(DeviceStateEnum.ON.name());
        deviceTerminalService.saveOrUpdate(deviceTerminal);
    }
//
//    //设备下线
    private void deviceDownline(Optional<NettySession> nettySessionOptional) {
        nettySessionOptional.ifPresent(session -> {
            String bizKey = session.getBizKey();
            IDeviceInfoService deviceTerminalService = SpringUtil.getBean(IDeviceInfoServiceImpl.class);
            IDeviceInfo deviceTerminal = deviceTerminalService.getById(bizKey);
            if(deviceTerminal == null){
                deviceTerminal = new IDeviceInfo();
                deviceTerminal.setDevicetime(DateUtil.now());
            }
            deviceTerminal.setOfflinetime(DateUtil.now());
            deviceTerminal.setStatus(String.valueOf(DeviceStateEnum.OFF.name()));
            deviceTerminalService.saveOrUpdate(deviceTerminal);
            log.info("---------更新设备状态为：{}，【deviceDownline】", DeviceStateEnum.OFF.name());
        });
    }


    //表示服务端与客户端连接建立
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();  //其实相当于一个connection
        /**
         * 调用channelGroup的writeAndFlush其实就相当于channelGroup中的每个channel都writeAndFlush
         * 先去广播，再将自己加入到channelGroup中
         */
        channelGroup.writeAndFlush(" 【服务器】 -" + channel.remoteAddress() + " 加入\n");
        channelGroup.add(channel);
    }


    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        InetSocketAddress remoteAddress = (InetSocketAddress) ctx.channel().remoteAddress();
        String clientIpPort = remoteAddress.getAddress().getHostAddress() + ":" + remoteAddress.getPort();
        log.info("Client IP:Port: {}", clientIpPort);
        Optional<NettySession> sessionOptional = NettySessionManager.getSession(ctx.channel());
        deviceDownline(sessionOptional);
        log.info("----------设备下线[channelInactive]----------");
        NettySessionManager.removeSession(ctx);
        super.channelInactive(ctx);
    }

    /**
     * 发生异常后的处理
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        InetSocketAddress remoteAddress = (InetSocketAddress) ctx.channel().remoteAddress();
        String clientIpPort = remoteAddress.getAddress().getHostAddress() + ":" + remoteAddress.getPort();
        log.info("Client IP:Port: {}", clientIpPort);
        Optional<NettySession> sessionOptional = NettySessionManager.getSession(ctx.channel());
        if (ctx.channel().isActive()) {
            if (cause instanceof SocketTimeoutException) {
                deviceDownline(sessionOptional);
                log.error("----------设备连接超时异常下线[exceptionCaught]----------");
            } else if (cause instanceof IOException) {
                deviceDownline(sessionOptional);
                log.error("----------设备网络异常下线[exceptionCaught]----------");
                log.error("Network exception occurred: {}", cause.getMessage(), cause);
            } else {
                deviceDownline(sessionOptional);
                log.error("----------设备未知异常下线[exceptionCaught]----------");
                log.error("Unexpected exception occurred: {}", cause.getMessage(), cause);
            }

            NettySessionManager.removeSession(ctx);
            if (NettySessionManager.getSession(ctx.channel()).isPresent()) {
                log.error("Session not fully removed, additional cleanup needed.");
                NettySessionManager.removeSession(ctx.channel());
            }
            log.error("----------设备异常下线，移除会话[exceptionCaught],{}", ctx.channel());
            ctx.close();
            log.info("----------设备异常下线，关闭通道[exceptionCaught]----------");
        } else {
            log.error("----------Channel已经不活跃,无需处理下线逻辑[exceptionCaught]----------");
        }
    }

//    @Override
//    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
//        InetSocketAddress remoteAddress = (InetSocketAddress) ctx.channel().remoteAddress();
//        String clientIpPort = remoteAddress.getAddress().getHostAddress() + ":" + remoteAddress.getPort();
//        log.info("Client IP:Port: {}", clientIpPort);
//        if (ctx.channel().isActive()) {
//            Optional<NettySession> sessionOptional = NettySessionManager.getSession(ctx.channel());
//            if (evt instanceof IdleStateEvent) {
//                IdleStateEvent event = (IdleStateEvent) evt;
//                switch (event.state()) {
//                    case READER_IDLE:
//                        log.info("----------客户端读取闲置超时异常下线[READER_IDLE]----------");
//                        break;
//                    case WRITER_IDLE:
//                        log.info("----------客户端写入闲置超时异常下线[WRITER_IDLE]----------");
//                        break;
//                    case ALL_IDLE:
//                        log.info("----------客户端全部闲置超时异常下线[ALL_IDLE]----------");
//                        break;
//                    default:
//                        log.info("---------客户端闲置超时异常下线,IdleState.{} ----------", event.state());
//                        break;
//                }
//                deviceDownline(sessionOptional);
//                NettySessionManager.removeSession(ctx);
//                ctx.channel().close();
//            } else {
//                super.userEventTriggered(ctx, evt);
//                log.info("----------客户端闲置超时异常下线,evt不是IdleStateEvent类型的事件,未清除通道信息[ALL_IDLE]----------{}", evt.getClass().getName());
//                deviceDownline(sessionOptional);
//            }
//        } else {
//            log.info("----------Channel已经不活跃,无需处理下线逻辑[userEventTriggered]----------");
//        }
//    }
}

